package pl.edu.agh.gt.data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;

public class RatesHistory {

	public String name;
	/** maps dates to indexes in list */
	protected TreeMap<Date, Integer> indexMap = new TreeMap<Date, Integer>();
	/** ordered by time */
	protected List<Rate> ratesList = new ArrayList<Rate>();
	
	/** if created as period, hold ref. to parent and idx of sublist */
	protected RatesHistory parent;
	protected Integer startIdx;
	protected Integer endIdx;	

	public RatesHistory(String n) {
		this.name = n;
		this.parent = null;
	}

	public Rate getRate(Date time) {
		return ratesList.get(indexMap.get(time));
	}
	
	public Rate getRate(int index) {
		return ratesList.get(index);
	}

	public RatesHistory getPeriod(Date start, Date end) {
		
		Integer startIndex = indexMap.ceilingEntry(start).getValue();
		Integer endIndexIncl = indexMap.floorEntry(end).getValue();
		assert (startIndex != null && endIndexIncl  != null) : "Period exceeds history timeline";
		
		return getPeriod(startIndex, endIndexIncl + 1);
	}
	
	public RatesHistory getPeriod(int startIndex, int endIndex) {
		
		RatesHistory newRates = new RatesHistory(name);
		newRates.parent = this;		
		newRates.startIdx = startIndex;
		newRates.endIdx = endIndex;		
		newRates.ratesList = ratesList.subList(newRates.startIdx, newRates.endIdx);
		
		int i = 0;
		for(Rate r : newRates.ratesList)
			newRates.indexMap.put(r.getTime(),i++);
		
		return newRates;
	}
	
	/**
	 * Shifts given period one rate ahead on parent history basis
	 */
	public void shift() {

		assert parent != null : "Shifted history is not a subperiod";
		startIdx++;
		endIdx++;
		assert endIdx <= parent.ratesList.size();
		
		Rate oldFirst = getFirstRate();
		
		ratesList = parent.ratesList.subList(startIdx, endIdx);
		indexMap.remove(oldFirst.getTime());
		indexMap.put(getLastRate().getTime(), ratesList.size() - 1);
	}
	
	public List<Rate> asSortedList () {		
		return ratesList;
	}

	public void addNextRate(Rate rate) {
		assert ratesList.size() > 0 ? rate.getTime().after(ratesList.get(ratesList.size()-1).getTime()) : true;
		ratesList.add(rate);
		indexMap.put(rate.getTime(), ratesList.size()-1);
	}

	public Rate getLastRate() {
		return ratesList.get(ratesList.size()-1);
	}
	
	public Rate getFirstRate() {
		return ratesList.get(0);
	}
	
	public int getLength () {
		return ratesList.size();
	}
}
